package com.frikinet.gestorepub.web.spring.repositories;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.Query;
import javax.jdo.annotations.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class JDOModelDAOImpl implements ModelDAO
{
	@Autowired
	private PersistenceManagerFactory factory;
	
	@Override
	@Transactional
	public <T> T get(Class<T> model, Object key)
	{
		T result = null;
		PersistenceManager pm = factory.getPersistenceManager();
		try
		{
			result = pm.getObjectById(model, key);
		}
		catch(JDOObjectNotFoundException e)
		{
			result = null;
		}
		finally
		{
			pm.close();
		}
		return result;
	}

	@Override
	@Transactional
	public <T> void persist(T object)
	{
		PersistenceManager pm = factory.getPersistenceManager();
		try
		{
			pm.makePersistent(object);
		}
		finally
		{
			pm.close();
		}
	}
	
	@SuppressWarnings("unchecked")
	@Override
	@Transactional
	public <T> T getUniqueQuery(Class<T> clazz, Object... params)
	{
		if(params.length%2!=0)
			throw new IllegalArgumentException("getUniqueQuery expects an even number of parameters");
		
		PersistenceManager pm = factory.getPersistenceManager();
		Query query = pm.newQuery(clazz);
		query.setUnique(true);
		
		T result;
		
		try
		{
			StringBuffer filter = new StringBuffer();
			StringBuffer declaredParams = new StringBuffer();
			List<Object> paramObjects = new ArrayList<Object>();
			
			for(int i=0;i < params.length; i = i +2)
			{
				Field field = clazz.getDeclaredField(params[i].toString());
				if(filter.length() > 0)
					filter.append(" && ");
				filter.append(String.format("%s == param%d", field.getName(), i/2));
				if(declaredParams.length() > 0)
					declaredParams.append(", ");
				declaredParams.append(String.format("%s param%d", field.getType().getName(), i/2));
				paramObjects.add(params[i+1]);
			}
			query.setFilter(filter.toString());
			query.declareParameters(declaredParams.toString());
			
			result = (T)query.executeWithArray(paramObjects.toArray());
		}
		catch (SecurityException e)
		{
			throw new IllegalArgumentException("Problem with params", e);
		}
		catch (NoSuchFieldException e)
		{
			throw new IllegalArgumentException("Problem with params", e);
		}
		finally
		{
			pm.close();
		}
		
		return result;
	}

}
